package com.s2paganini.util 
{
	import flash.display.DisplayObject;
	import flash.display.Sprite;
	import flash.display.Stage;
	import flash.events.Event;
	import flash.events.MouseEvent;
	import flash.geom.Rectangle;
	import flash.utils.getQualifiedClassName;	

	/**
	 * @author siLvio paganini | s2paganini.com
	 * @purpose Scroll Class 
	 */

	public class Scroll 
	{
		private static var instance : Scroll;

		private var scrollTrk : *;
		private var contentMain : DisplayObject;
		private var scrollFace : Sprite;
		private var maskedView : DisplayObject;
		private var btnUp : Sprite;
		private var btnDown : Sprite;

		private var scrollHeight : Number;
		private var contentHeight : Number;
		private var scrollFaceHeight : Number;
		private var maskHeight : Number;
		private var initPosition : Number;
		private var initContentPos : Number;
		private var finalContentPos : Number;
		private var left : Number;
		private var top : Number;
		private var right : Number;
		private var bottom : Number;
		private var bottom2 : Number;
		private var dy : Number = 0;
		private var speed : Number = 5;
		private var moveVal : Number;
		private var currPos : Number = 0;
		private var rect1 : Rectangle;
		private var stage : Stage;
		private var mouseWheelSupport : Boolean;

		/*
		 * @param _scrollTrk Track Reference to Drag, could be a Rectangle or a DisplayObject
		 * @param _contentMain Content to Scroll
		 * @param _scrollFace Dragger
		 * @param _maskedView Content Mask
		 * @param _stage Stage Reference
		 * @param _btnUp Optional Button UP
		 * @param _btnDown Optional Button DOWN
		 */

		public function Scroll(pvt : PrivateClass)
		{
		}

		public static function getInstance() : Scroll
		{
			if (Scroll.instance == null) {
				Scroll.instance = new Scroll(new PrivateClass());
			}
			return Scroll.instance;	
		}

		public function setVars(_scrollTrk : *, 
							   _contentMain : DisplayObject, 
							   _scrollFace : Sprite, 
							   _maskedView : DisplayObject, 
							   _stage : Stage,
							   _btnUp : Sprite = null, 
							   _btnDown : Sprite = null,
							   mouseWheel : Boolean = true) : void
		{
			scrollTrk = _scrollTrk;
			contentMain = _contentMain;	
			scrollFace = _scrollFace;
			maskedView = _maskedView;
			btnUp = _btnUp;		
			btnDown = _btnDown;
			stage = _stage;
			mouseWheelSupport = mouseWheel;
		}

		public function start() : void
		{
			scrollHeight = scrollTrk["height"];
			contentHeight = contentMain.height;
			scrollFaceHeight = scrollFace.height;
			maskHeight = maskedView.height;
			
			initContentPos = contentMain.y;
			finalContentPos = maskHeight - contentHeight + initContentPos;
			
			if(getQualifiedClassName(scrollTrk) == "flash.geom::Rectangle") {
				var tempScrollTrackRectangle : Rectangle = scrollTrk as Rectangle;
				initPosition = scrollFace.y = tempScrollTrackRectangle.top;
				left = tempScrollTrackRectangle.x;
				top = tempScrollTrackRectangle.y;
				bottom2 = scrollTrk["height"] - scrollFaceHeight + tempScrollTrackRectangle.y;
			} else {
				var tempScrollTrackDisplay : DisplayObject = scrollTrk as DisplayObject;
				initPosition = scrollFace.y = tempScrollTrackDisplay.y;
				left = tempScrollTrackDisplay.x;
				top = tempScrollTrackDisplay.y;
				bottom2 = scrollTrk["height"] - scrollFaceHeight + tempScrollTrackDisplay.y;
			}
			
			right = 0;
			bottom = scrollTrk["height"] - scrollFaceHeight;
			
			moveVal = (contentHeight - maskHeight) / (scrollHeight - scrollFaceHeight);
			
			rect1 = new Rectangle(left, top, right, bottom);

			scrollFace.addEventListener(MouseEvent.MOUSE_DOWN, scrollMouseListener);
			scrollFace.addEventListener(MouseEvent.MOUSE_UP, scrollMouseListener);
			
			if(btnUp) {
				btnUp.addEventListener(MouseEvent.MOUSE_DOWN, buttonsListeners);
				btnUp.addEventListener(MouseEvent.MOUSE_UP, buttonsListeners);
				btnUp.addEventListener(MouseEvent.MOUSE_OUT, buttonsListeners);
			}
			
			if(btnDown) {
				btnDown.addEventListener(MouseEvent.MOUSE_DOWN, buttonsListeners);
				btnDown.addEventListener(MouseEvent.MOUSE_UP, buttonsListeners);
				btnDown.addEventListener(MouseEvent.MOUSE_OUT, buttonsListeners);
			}
			
			if(mouseWheelSupport) {
				stage.addEventListener(MouseEvent.MOUSE_WHEEL, wheelListener);
				contentMain.addEventListener(Event.REMOVED_FROM_STAGE, stopsListeners);
			}
			
			checkScroll();
		}

		private function stopsListeners(event : Event) : void
		{
			stage.removeEventListener(MouseEvent.MOUSE_WHEEL, wheelListener);
		}

		private function wheelListener(event : MouseEvent) : void
		{
			scrollFace.y = Math.min(Math.max(scrollFace.y - event.delta, rect1.top), rect1.bottom);
			scrollMove();
		}

		private function scrollMouseListener(event : MouseEvent) : void
		{
			switch (event.type) {
				case "mouseDown":
					currPos = scrollFace.y;
					scrollFace.startDrag(false, rect1);
					scrollFace.addEventListener(Event.ENTER_FRAME, scrollMove);
					stage.addEventListener(MouseEvent.MOUSE_UP, releaseOut);
					break;
					
				case "mouseUp":
					scrollFace.stopDrag();
					scrollFace.removeEventListener(Event.ENTER_FRAME, scrollMove);
					break;
			}	
		}

		private function scrollMove(event : Event = null) : void 
		{
			dy = Math.abs(initPosition - scrollFace.y);
			contentMain.y = Math.round(dy * -1 * moveVal + initContentPos);
		};

		private function releaseOut(event : MouseEvent) : void
		{
			if (event.target != scrollFace) {
				scrollFace.stopDrag();
				scrollFace.removeEventListener(Event.ENTER_FRAME, scrollMove);
			}
			stage.removeEventListener(MouseEvent.MOUSE_UP, releaseOut);
		};

		private function buttonsListeners(event : *) : void
		{
			var tempTarget : Sprite = event["target"] as Sprite;
			
			switch (event["type"]) {
				case "mouseUp":
					tempTarget.removeEventListener(Event.ENTER_FRAME, buttonsListeners);
					break;
				
				case "mouseDown":
					tempTarget.addEventListener(Event.ENTER_FRAME, buttonsListeners);
					break;
					
				case "enterFrame":
					if(tempTarget == btnUp) {
						if (contentMain.y >= initContentPos || scrollFace.y <= top) {
							contentMain.y = initContentPos;
							scrollFace.y = top;
						}else {
							scrollFace.y -= speed / moveVal;
							contentMain.y += speed;
						}
					} else {
						if (contentMain.y <= finalContentPos || scrollFace.y >= bottom) {
							contentMain.y = finalContentPos;
							scrollFace.y = bottom2;
						}else {
							scrollFace.y += speed / moveVal;
							contentMain.y -= speed;
						}
					}
					break;
					
				case "mouseOut":
					tempTarget.removeEventListener(Event.ENTER_FRAME, buttonsListeners);
					break;
			}
		}

		public function checkScroll() : void
		{
			if (contentHeight <= maskHeight) {
				scrollFace.visible = false;
				if(getQualifiedClassName(scrollTrk) != "flash.geom::Rectangle") scrollTrk["visible"] = false; 
				if(btnUp) btnUp.mouseEnabled = false;
				if(btnDown) btnDown.mouseEnabled = false;
			} else {
				scrollFace.visible = true;
				if(getQualifiedClassName(scrollTrk) != "flash.geom::Rectangle") scrollTrk["visible"] = true;
				if(btnUp) btnUp.mouseEnabled = true;
				if(btnDown) btnDown.mouseEnabled = true;
			}
		}
	}
}

class PrivateClass
{
	public function PrivateClass()
	{
	}
}